#include "mainwindow.h"

#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent),
      ui(new Ui::MainWindow),
      m_switcher(nullptr),
      m_toggleMaskMenu(nullptr),
      m_shadowWidget(nullptr),
      m_prevCheckedBtnInfo() {
  ui->setupUi(this);
  m_switcher = new StyleSwitcher(ui->label);
  initGrpBox();
  initBtnGrp();
  initTogglePart();
  initFileOperation();
  limitInput();  //输入限制
  this->show();
}

MainWindow::~MainWindow() {
  DELETE_PTR(m_switcher)
  DELETE_PTR(m_toggleMaskMenu)
  DELETE_PTR(m_shadowWidget)

  delete ui;
}

void MainWindow::limitInput() {
  // 6 ～ 8 位数字
  QRegExp rxOne("^[0-9]{6,8}$");
  //字母和数字
  QRegExp rxTwo("^[A-Za-z0-9]+$");
  //限定汉字或字母输入 总共 10 位
  QRegExp rxThree(
      "^[\\x4e00-\\x9fa5]{1,15}(\\x00B7)?[\\x4e00-\\x9fff]{1,10}$|^[a-zA-Z][ "
      "a-zA-Z]{0,9}$");
  // 小数点前 1 ～ 2 位数字，小数点后 0 ～ 1 位数字
  QRegExp rxFour("^[0-9]{1,2}(\\.[0-9])?$");
  // 不以 # 开头的字符，最大长度为 3
  QRegExp regFive("[^#]{0,3}");

  ui->lineEdit->setValidator(new QRegExpValidator(rxOne, this));
}
void MainWindow::initGrpBox() {
  ui->label_1->setText(tr("no password"));

  ui->lineEdit->setEchoMode(QLineEdit::Password);
  ui->lineEdit->setPlaceholderText(tr("input password"));
  ui->lineEdit->setFocusPolicy(Qt::StrongFocus);
  QMetaObject::Connection con = connect(
      ui->lineEdit,
      static_cast<void (QLineEdit::*)(const QString&)>(&QLineEdit::textChanged),
      [&](const QString& text) {
        QString str = text.simplified();
        str = str.isEmpty() ? tr("no password") : str;
        ui->label_1->setText(str);
      });

  ui->pushButton->setFocusPolicy(Qt::StrongFocus);
  ui->pushButton->setCheckable(true);
  ui->pushButton->setChecked(false);
  ui->pushButton->setText(tr("Can Use ComboBox"));
  connect(ui->pushButton, &QPushButton::toggled, this, [this](bool checked) {
    if (checked) {
      ui->pushButton->setText(tr("Cannot Use ComboBox"));
    } else {
      ui->pushButton->setText(tr("Can Use ComboBox"));
    }
  });
  connect(ui->comboBox, SIGNAL(clicked()), this, SLOT(slotComboBoxClicked()));
}

void MainWindow::initBtnGrp() {
  ui->buttonGroup_1->setExclusive(true);
  ui->buttonGroup_1->setId(ui->pushButton_1, static_cast<int>(Color::RED));
  ui->buttonGroup_1->setId(ui->pushButton_2, static_cast<int>(Color::YELLO));
  ui->buttonGroup_1->setId(ui->pushButton_3, static_cast<int>(Color::GREEN));

  connect(ui->buttonGroup_1, SIGNAL(buttonClicked(QAbstractButton*)), this,
          SLOT(slotBtnGrpClicked(QAbstractButton*)));
}

void MainWindow::initTogglePart() {
  ui->widget_shadow->setObjectName("widget_shadow");

  // toggle mask 按钮添加菜单
  m_toggleMaskMenu = new QMenu(ui->pushButton_toggle_mask);
  // 添加菜单项
  QAction* showMaskAction = m_toggleMaskMenu->addAction(tr("show mask"));
  QAction* hideMaskAction = m_toggleMaskMenu->addAction(tr("hide mask"));

  // 为按钮设置菜单
  ui->pushButton_toggle_mask->setMenu(m_toggleMaskMenu);

  // 连接菜单项的触发信号到槽函数
  connect(showMaskAction, &QAction::triggered, this,
          &MainWindow::showMaskLayer);
  connect(hideMaskAction, &QAction::triggered, [&]() {
    if (m_shadowWidget) {
      m_shadowWidget->close();
      m_shadowWidget = nullptr;
    }
  });
}

void MainWindow::initFileOperation() {
  ui->buttonGroup_src_file->setExclusive(true);
  ui->buttonGroup_src_file->setId(ui->pushButton_src_file,
                                  static_cast<int>(File_Oper_Src::SRC_FILE));
  ui->buttonGroup_src_file->setId(ui->pushButton_src_files,
                                  static_cast<int>(File_Oper_Src::SRC_FILES));
  ui->buttonGroup_src_file->setId(ui->pushButton_src_dir,
                                  static_cast<int>(File_Oper_Src::SRC_DIR));
  ui->buttonGroup_src_file->setId(
      ui->pushButton_clear_src,
      static_cast<int>(File_Oper_Src::SRC_TEXT_CLEAR));

  ui->buttonGroup_target_file->setExclusive(true);
  ui->buttonGroup_target_file->setId(
      ui->pushButton_target_dir,
      static_cast<int>(File_Oper_Target::TARGET_DIR));
  ui->buttonGroup_target_file->setId(
      ui->pushButton_clear_target,
      static_cast<int>(File_Oper_Target::TARGET_TEXT_CLEAR));

  ui->buttonGroup_operation->setExclusive(true);
  ui->buttonGroup_operation->setId(ui->pushButton_copy,
                                   static_cast<int>(File_Oper::FILE_COPY));
  ui->buttonGroup_operation->setId(ui->pushButton_move,
                                   static_cast<int>(File_Oper::FILE_MOVE));
  ui->buttonGroup_operation->setId(ui->pushButton_delete,
                                   static_cast<int>(File_Oper::FILE_DELETE));

  ui->plainTextEdit_src->clear();
  ui->plainTextEdit_target->clear();

  ui->plainTextEdit_src->setReadOnly(true);
  ui->plainTextEdit_target->setReadOnly(true);

  ui->pushButton_copy->setEnabled(false);
  ui->pushButton_move->setEnabled(false);
  ui->pushButton_delete->setEnabled(false);

  connect(ui->buttonGroup_src_file, SIGNAL(buttonClicked(QAbstractButton*)),
          this, SLOT(slotBtnFileOperClicked(QAbstractButton*)));
  connect(ui->buttonGroup_target_file, SIGNAL(buttonClicked(QAbstractButton*)),
          this, SLOT(slotBtnFileOperClicked(QAbstractButton*)));
  connect(ui->buttonGroup_operation, SIGNAL(buttonClicked(QAbstractButton*)),
          this, SLOT(slotBtnFileOperClicked(QAbstractButton*)));
}

void MainWindow::slotComboBoxClicked() {
  ui->comboBox->setState(!ui->pushButton->isChecked());
}

void MainWindow::slotBtnGrpClicked(QAbstractButton* button) {
  QPushButton* clickedBtn = dynamic_cast<QPushButton*>(button);
  QString strText = clickedBtn->text();
  if (m_prevCheckedBtnInfo.checkedBtn == clickedBtn) {
    return;
  } else if (m_prevCheckedBtnInfo.checkedBtn != nullptr) {
    m_prevCheckedBtnInfo.checkedBtn->setText(m_prevCheckedBtnInfo.strText);
  }
  m_prevCheckedBtnInfo.checkedBtn = clickedBtn;
  m_prevCheckedBtnInfo.strText = strText;
  clickedBtn->setText(tr("Hit"));
}

void MainWindow::showMaskLayer() {
  if (m_shadowWidget == nullptr) {
    m_shadowWidget = new ShadowWidget(ui->widget_shadow);
  }
  m_shadowWidget->setWindowModality(Qt::NonModal);
  m_shadowWidget->setFocusPolicy(Qt::NoFocus);
  m_shadowWidget->setVisible(true);
}

void MainWindow::slotBtnFileOperClicked(QAbstractButton* button) {
  QButtonGroup* btnGrp = dynamic_cast<QButtonGroup*>(sender());

  // 源文件操作组
  if (btnGrp->objectName().compare(ui->buttonGroup_src_file->objectName()) ==
      0) {
    File_Oper_Src id = static_cast<File_Oper_Src>(btnGrp->id(button));
    switch (id) {
      case File_Oper_Src::SRC_FILE:
        openSingleFile();
        break;
      case File_Oper_Src::SRC_FILES:
        openMultipleFiles();
        break;
      case File_Oper_Src::SRC_DIR:
        openSrcDir();
        break;
      case File_Oper_Src::SRC_TEXT_CLEAR:
        ui->plainTextEdit_src->clear();
        ui->pushButton_copy->setEnabled(false);
        ui->pushButton_move->setEnabled(false);
        ui->pushButton_delete->setEnabled(false);
        break;
      default:
        break;
    }
  }

  // 目标文件操作组
  if (btnGrp->objectName().compare(ui->buttonGroup_target_file->objectName()) ==
      0) {
    File_Oper_Target id = static_cast<File_Oper_Target>(btnGrp->id(button));
    switch (id) {
      case File_Oper_Target::TARGET_DIR:
        openTargetDir();
        break;
      case File_Oper_Target::TARGET_TEXT_CLEAR:
        ui->plainTextEdit_target->clear();
        ui->pushButton_copy->setEnabled(false);
        ui->pushButton_move->setEnabled(false);
        break;
      default:
        break;
    }
  }

  // 文件操作
  if (btnGrp->objectName().compare(ui->buttonGroup_operation->objectName()) ==
      0) {
    File_Oper id = static_cast<File_Oper>(btnGrp->id(button));
    fileOperation(id);
  }
}
void MainWindow::showFileOperationMask() {
  if (m_shadowWidget) {
    m_shadowWidget->close();
    m_shadowWidget = nullptr;
  }
  m_shadowWidget = new ShadowWidget(ui->groupBox_file_operation);
  m_shadowWidget->setWindowModality(Qt::NonModal);
  m_shadowWidget->setFocusPolicy(Qt::NoFocus);
  m_shadowWidget->setVisible(true);

  ui->pushButton_toggle_mask->setDisabled(true);
}

void MainWindow::openSingleFile() {
  QString caption(tr("Open Single File"));  //对话框标题
  QString dir = QCoreApplication::
      applicationDirPath();  //获取应用程序的路径作为打开对话框时默认进入的目录
  QString filter(tr("All files(*.*)"));  //文件过滤器

  QString fileName = QFileDialog::getOpenFileName(this, caption, dir, filter);

  if (!fileName.isEmpty()) {
    ui->plainTextEdit_src->clear();
    ui->plainTextEdit_src->setPlainText(fileName.trimmed());  // 移除首尾的空格
    ui->lineEdit_file_name->setEnabled(true);
    ui->pushButton_delete->setEnabled(true);
    ui->pushButton_copy->setEnabled(
        !ui->plainTextEdit_target->toPlainText().isEmpty());
    ui->pushButton_move->setEnabled(
        !ui->plainTextEdit_target->toPlainText().isEmpty());
  }
}

void MainWindow::openMultipleFiles() {
  QString caption(tr("Open Multiple Files"));  //对话框标题
  QString dir = QCoreApplication::
      applicationDirPath();  //获取应用程序的路径作为打开对话框时默认进入的目录

  QString filter(tr("All files(*.*)"));  //文件过滤器
  QStringList fileList =
      QFileDialog::getOpenFileNames(this, caption, dir, filter);
  for (QString& s : fileList) {
    ui->plainTextEdit_src->appendPlainText(s.trimmed());
    ui->lineEdit_file_name->setEnabled(false);
    ui->pushButton_delete->setEnabled(true);
    ui->pushButton_copy->setEnabled(
        !ui->plainTextEdit_target->toPlainText().isEmpty());
    ui->pushButton_move->setEnabled(
        !ui->plainTextEdit_target->toPlainText().isEmpty());
  }
}

// 单个目录
void MainWindow::openSrcDir() {
  QString caption(tr("Open Directory"));  //对话框标题
  QString dir = QCoreApplication::
      applicationDirPath();  //获取应用程序的路径作为打开对话框时默认进入的目录
  QString selectedDir = QFileDialog::getExistingDirectory(
      this, caption, dir,
      QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
  if (!selectedDir.isEmpty()) {
    ui->plainTextEdit_src->clear();
    ui->plainTextEdit_src->setPlainText(selectedDir.trimmed());
    ui->lineEdit_file_name->setEnabled(false);
    ui->pushButton_delete->setEnabled(true);
    ui->pushButton_copy->setEnabled(
        !ui->plainTextEdit_target->toPlainText().isEmpty());
    ui->pushButton_move->setEnabled(
        !ui->plainTextEdit_target->toPlainText().isEmpty());
  }
}

// 单个目录
void MainWindow::openTargetDir() {
  QString caption(tr("Open Directory"));  //对话框标题
  QString dir = QCoreApplication::
      applicationDirPath();  //获取应用程序的路径作为打开对话框时默认进入的目录
  QString selectedDir = QFileDialog::getExistingDirectory(
      this, caption, dir,
      QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
  if (!selectedDir.isEmpty()) {
    ui->plainTextEdit_target->setPlainText(selectedDir.trimmed());
    ui->pushButton_copy->setEnabled(
        !ui->plainTextEdit_src->toPlainText().isEmpty());
    ui->pushButton_move->setEnabled(
        !ui->plainTextEdit_src->toPlainText().isEmpty());
  }
}

void MainWindow::fileOperation(File_Oper buttonId) {
  // 源文件为空
  QString srcText = ui->plainTextEdit_src->toPlainText();
  if (srcText.isEmpty()) {
    ui->pushButton_copy->setEnabled(false);
    return;
  }

  showFileOperationMask();

  QStringList srcFiles = srcText.split("\n");  // 按换行符分割文本为字符串列表
  QString targetDir = ui->plainTextEdit_target->toPlainText().trimmed();

  QFuture<bool> future;
  // 只有一行，判断是单个文件还是目录
  if (srcFiles.size() < 2) {
    QFileInfo srcFileInfo(srcText);
    if (srcFileInfo.isFile()) {
      QString srcFileName = srcFileInfo.fileName();
      QString targetFileName = ui->lineEdit_file_name->text().trimmed();
      targetFileName = targetFileName.isEmpty() ? srcFileName : targetFileName;
      QString targetPath = targetDir + "/" + targetFileName;
      if (buttonId == File_Oper::FILE_DELETE) {
        targetPath.clear();
      }

      future = QtConcurrent::run(this, &MainWindow::operateAFile, buttonId,
                                 srcText, targetPath);
    } else {
      future = QtConcurrent::run(this, &MainWindow::operateDir, buttonId,
                                 srcText, targetDir);
    }
  } else {
    // 多个文件 可能包含目录
    future = QtConcurrent::run(this, &MainWindow::operateFiles, buttonId,
                               srcFiles, targetDir);
  }

  // 启动后台线程进行文件操作
  QFutureWatcher<bool>* watcher = new QFutureWatcher<bool>(this);

  // 连接完成信号与槽
  connect(watcher, &QFutureWatcher<bool>::finished, this,
          [this, watcher, buttonId]() {
            watcher->deleteLater();
            if (buttonId == File_Oper::FILE_DELETE ||
                buttonId == File_Oper::FILE_MOVE) {
              ui->plainTextEdit_src->clear();
            }
            // hideMask 是你定义来隐藏遮罩层的函数
            if (m_shadowWidget) {
              m_shadowWidget->close();
              m_shadowWidget = nullptr;
              ui->pushButton_toggle_mask->setEnabled(true);
            }
            // bool success = watcher->future().result();
          });

  watcher->setFuture(future);
}

bool MainWindow::operateAFile(File_Oper buttonId, QString& srcPath,
                              QString& targetPath) {
  bool succeed = false;
  QString oper("");
  switch (buttonId) {
    case File_Oper::FILE_COPY:
      if (QFile::copy(srcPath, targetPath)) {
        succeed = true;
        oper = tr("Copy");
      }
      break;
    case File_Oper::FILE_MOVE:
      if (QFile::rename(srcPath, targetPath)) {
        succeed = true;
        oper = tr("Move");
      }
      break;
    case File_Oper::FILE_DELETE:
      if (QFile::remove(srcPath)) {
        succeed = true;
        oper = tr("Delete");
      }
      break;
  }
  if (!succeed) {
    QMessageBox::warning(nullptr, tr("% Error").arg(oper),
                         tr("Could not %1 file: ").arg(oper) + srcPath);
    return false;
  }

  return true;
}

bool MainWindow::operateDir(File_Oper buttonId, QString& srcDir,
                            QString& targetDir) {
  QDir fromDir(srcDir);
  QDir toDir(targetDir);

  // 如果是删除操作 删除目录
  if (buttonId == File_Oper::FILE_DELETE) {
    if (!fromDir.removeRecursively()) {
      QMessageBox::warning(nullptr, tr("Delete Error"),
                           tr("Could not Delete dir : ") + srcDir);
      return false;
    }
    return true;
  }
  if (!toDir.exists()) {
    if (!toDir.mkdir(toDir.absolutePath())) {
      return false;
    }  // 创建目标目录
  }

  bool succeed = true;
  QString oper("");
  // 文件
  for (QString& fileName : fromDir.entryList(QDir::Files)) {
    QString srcFilePath = srcDir + "/" + fileName;
    QString targetFilePath = targetDir + "/" + fileName;
    if (buttonId == File_Oper::FILE_COPY) {
      if (!QFile::copy(srcFilePath, targetFilePath)) {
        succeed = false;
        oper = tr("Copy");
      }
    } else if (buttonId == File_Oper::FILE_MOVE) {
      if (!QFile::rename(srcFilePath, targetFilePath)) {
        succeed = false;
        oper = tr("Move");
      }
    }
    if (!succeed) {
      QMessageBox::warning(nullptr, tr("%1 Error").arg(oper),
                           tr("Could not %1 file: ").arg(oper) + srcFilePath);
    }
  }

  // 子目录
  for (QString& dirName :
       fromDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
    QString srcSubDirPath = srcDir + "/" + dirName;
    QString targetSubDirPath = targetDir + "/" + dirName;

    if (buttonId == File_Oper::FILE_COPY) {
      if (!operateDir(buttonId, srcSubDirPath, targetSubDirPath)) {
        succeed = false;
        oper = tr("Copy");
      }
    } else if (buttonId == File_Oper::FILE_MOVE) {
      if (!operateDir(buttonId, srcSubDirPath, targetSubDirPath)) {
        succeed = false;
        oper = tr("Move");
      }
    }
    if (!succeed) {
      QMessageBox::warning(nullptr, tr("%1 Error").arg(oper),
                           tr("Could not %1 dir: ").arg(oper) + srcSubDirPath);
    }
  }

  return succeed;
}

// 操作多个文件，可能包含目录
bool MainWindow::operateFiles(File_Oper buttonId, QStringList& srcFiles,
                              QString& targetDir) {
  bool succeed = true;
  // 多个源文件 可能包含目录
  for (QString& srcPath : srcFiles) {
    QFileInfo srcFileInfo(srcPath);
    QString srcFileName = srcFileInfo.fileName();
    QString targetPath = targetDir + "/" + srcFileName;

    if (srcFileInfo.isFile()) {
      if (!operateAFile(buttonId, srcPath, targetPath)) {
        succeed = false;
      }
    } else {
      if (!operateDir(buttonId, srcPath, targetPath)) {
        succeed = false;
      }
    }
  }

  return succeed;
}
